﻿namespace ScrumLite.WebUx.Tests
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using ScrumLite.Services;
    using ScrumLite.Services.Contracts;
    using ScrumLite.WebUx.Controllers;
    using ScrumLite.WebUx.Models;
    using System.Globalization;
    using System.Configuration;
    using System.Web.Mvc;

    /// <summary>
    /// Summary description for CommitmentsControllerFixture
    /// </summary>
    [TestClass]
    public class CommitmentsControllerFixture
    {        
        [TestMethod]
        public void ShouldControllerPassStandupDatesToView()
        {
            MockCommitmentsService service = new MockCommitmentsService();
            TestableCommitmentsController controller = new TestableCommitmentsController(service);
            string projectId = Guid.NewGuid().ToString();
            InitializeTodayCommitments(projectId, service);

            controller.StandUps(projectId);
            
            Assert.IsNotNull(controller.DataToShow);
            Assert.IsInstanceOfType(controller.DataToShow, typeof(StandupListViewData));
            Assert.AreEqual(5, ((StandupListViewData)controller.DataToShow).StandupDates.Count);
        }

        [TestMethod]
        public void ShouldControllerPassProjectUriAndNameToView()
        {
            TestableCommitmentsController controller = new TestableCommitmentsController();
            
            controller.StandUps(Guid.NewGuid().ToString());

            Assert.IsNotNull(controller.DataToShow);
            Assert.IsNotNull(((StandupListViewData)controller.DataToShow).ProjectName);
            Assert.IsNotNull(((StandupListViewData)controller.DataToShow).ProjectId);            
            Assert.IsTrue(((StandupListViewData)controller.DataToShow).ProjectName.Length > 0);
            Assert.IsTrue(((StandupListViewData)controller.DataToShow).ProjectId.Length > 0);
        }

        [TestMethod]
        public void ShouldControllerPassStandupDatesButExcludeToday()
        {
            TestableCommitmentsController controller = new TestableCommitmentsController();

            controller.StandUps(Guid.NewGuid().ToString());
            Collection<DateTime> dates = ((StandupListViewData)controller.DataToShow).StandupDates;
            
            Assert.IsFalse(dates.Contains(DateTime.Now.Date));
        }

        [TestMethod]
        public void ShouldSendAnEmptyStandupDatesListIfServiceReturnsZero()
        {
            TestableCommitmentsController controller = new TestableCommitmentsController();
            MockCommitmentsService.DatesToReturn.Clear();

            controller.StandUps(Guid.NewGuid().ToString());
            Collection<DateTime> dates = ((StandupListViewData)controller.DataToShow).StandupDates;

            Assert.AreEqual(0, dates.Count);
        }

        [TestMethod]
        public void ShouldControllerPassProjectNameToCommitmentsStandUpsView()
        {
            TestableCommitmentsController controller = new TestableCommitmentsController();

            controller.StandUps("12184e41-b84d-4c2f-9251-cb0f8e8d7ddb");

            Assert.IsNotNull(controller.DataToShow);            
            Assert.AreEqual("Colorado-v1", ((StandupListViewData)controller.DataToShow).ProjectName);
        }
        
        [TestMethod]
        public void ShouldControllerPassCompletedCommitmentsToView()
        {
            TestableCommitmentsController controller = new TestableCommitmentsController();

            controller.Read(Guid.NewGuid().ToString(), MockCommitmentsService.fechaBase.Date);

            Assert.IsNotNull(controller.DataToShow);
            Assert.IsInstanceOfType(controller.DataToShow, typeof(CommitmentsReadViewData));
            Assert.AreEqual(2, ((CommitmentsReadViewData)controller.DataToShow).CompletedCommitments.Count);
            Assert.AreEqual(0, ((CommitmentsReadViewData)controller.DataToShow).CompletedCommitments[0].Left);
        }

        [TestMethod]
        public void ShouldControllerPassUncompletedCommitmentsToView()
        {
            TestableCommitmentsController controller = new TestableCommitmentsController();

            controller.Read(Guid.NewGuid().ToString(), MockCommitmentsService.fechaBase.Date);

            Assert.IsNotNull(controller.DataToShow);
            Assert.IsInstanceOfType(controller.DataToShow, typeof(CommitmentsReadViewData));
            Assert.AreEqual(2, ((CommitmentsReadViewData)controller.DataToShow).UncompletedCommitments.Count);
            Assert.IsTrue(((CommitmentsReadViewData)controller.DataToShow).UncompletedCommitments[0].Left > 0);
        }

        [TestMethod]
        public void ShouldControllerPassProjectNameToCommitmentsReadView()
        {
            TestableCommitmentsController controller = new TestableCommitmentsController();

            controller.Read("12184e41-b84d-4c2f-9251-cb0f8e8d7ddb", MockCommitmentsService.fechaBase.Date);

            Assert.IsNotNull(controller.DataToShow);
            Assert.AreEqual("Colorado-v1", ((CommitmentsReadViewData)controller.DataToShow).ProjectName);
        }

        [TestMethod]
        public void ShouldControllerSendCommitmentsOrderedByAscendant()
        {
            TestableCommitmentsController controller = new TestableCommitmentsController();

            controller.Read(Guid.NewGuid().ToString(), MockCommitmentsService.fechaBase.Date);

            Collection<Commitment> commitments;

            commitments = ((CommitmentsReadViewData)controller.DataToShow).UncompletedCommitments;
            Assert.IsTrue(String.Compare(commitments[0].CreatedBy, commitments[1].CreatedBy, StringComparison.Ordinal) < 0);

            commitments = ((CommitmentsReadViewData)controller.DataToShow).CompletedCommitments;
            Assert.IsTrue(String.Compare(commitments[0].CreatedBy, commitments[1].CreatedBy, StringComparison.Ordinal) < 0);
        }

        [TestMethod]
        public void ShouldAddCommitmentOnSaveWithEmptyCommitmentId()
        {
            MockCommitmentsService service = new MockCommitmentsService();
            TestableCommitmentsController controller = new TestableCommitmentsController(service);
            MockHelpers.SetupMocks(controller);

            controller.Save(Guid.NewGuid().ToString(), String.Empty, "New Commitment", "John Foo", "Some verification", DateTime.Now, 2, 0);

            Assert.IsTrue(service.AddCommitmentCalled);
            Assert.AreEqual("New Commitment", service.CommitmentAdded.Title);
        }

        [TestMethod]
        public void ShouldDeleteCommitment()
        {
            MockCommitmentsService service = new MockCommitmentsService();
            TestableCommitmentsController controller = new TestableCommitmentsController(service);
            MockHelpers.SetupMocks(controller);
            string projectId = Guid.NewGuid().ToString();

            controller.Save(projectId, String.Empty, "New Commitment", "John Foo", "Some verification", DateTime.Now, 2, 0);

            controller.Delete(projectId,Guid.NewGuid().ToString(),DateTime.Now);
            
            Assert.IsTrue(service.DeleteCommitmentCalled);
        }

        [TestMethod]
        public void ShouldRenderCommitmentsWithData()
        {
            string mockProjectUri = "AF06A611-12CE-4C06-B3AD-E2754D12D516";
            MockCommitmentsService service = new MockCommitmentsService();
            TestableCommitmentsController controller = new TestableCommitmentsController(service);

            controller.CommitmentsMetrics(mockProjectUri);

            Assert.AreEqual("CommitmentsMetrics", controller.ViewToShow);
            Assert.IsInstanceOfType(controller.DataToShow, typeof(CommitmentsMetricsData));
            Assert.IsInstanceOfType(controller.DataToShow, typeof(ContextViewData));
        }

        [TestMethod]
        public void ShouldCallGetWeeklyCommitments()
        {
            string mockProjectUri = "AF06A611-12CE-4C06-B3AD-E2754D12D516";
            MockCommitmentsService commitmentsService = new MockCommitmentsService();
            InitializeCommitmentsData(mockProjectUri, commitmentsService);
            TestableCommitmentsController controller = new TestableCommitmentsController(commitmentsService);

            controller.CommitmentsMetrics(mockProjectUri);

            Assert.IsTrue(commitmentsService.GetWeeklyCommitmentsCalled);
            Assert.IsNotNull(((CommitmentsMetricsData)controller.DataToShow).WeeklyOpenCommitmentsCount);
            Assert.IsNotNull(((CommitmentsMetricsData)controller.DataToShow).WeeklyClosedCommitmentsCount);
            Assert.AreEqual(5, ((CommitmentsMetricsData)controller.DataToShow).WeeklyOpenCommitmentsCount.Count);
            Assert.AreEqual(5, ((CommitmentsMetricsData)controller.DataToShow).WeeklyClosedCommitmentsCount.Count);
            Assert.AreEqual(3, ((CommitmentsMetricsData)controller.DataToShow).WeeklyOpenCommitmentsCount[2]);
            Assert.AreEqual(3, ((CommitmentsMetricsData)controller.DataToShow).WeeklyOpenCommitmentsCount[3]);
            Assert.AreEqual(2, ((CommitmentsMetricsData)controller.DataToShow).WeeklyOpenCommitmentsCount[4]);
            Assert.AreEqual(1, ((CommitmentsMetricsData)controller.DataToShow).WeeklyOpenCommitmentsCount[5]);
            Assert.AreEqual(1, ((CommitmentsMetricsData)controller.DataToShow).WeeklyClosedCommitmentsCount[2]);
            Assert.AreEqual(3, ((CommitmentsMetricsData)controller.DataToShow).WeeklyClosedCommitmentsCount[3]);
            Assert.AreEqual(2, ((CommitmentsMetricsData)controller.DataToShow).WeeklyClosedCommitmentsCount[4]);
            Assert.AreEqual(4, ((CommitmentsMetricsData)controller.DataToShow).WeeklyClosedCommitmentsCount[5]);
        }

        private static void InitializeTodayCommitments(string projectId, MockCommitmentsService commitmentsService)
        {
            // commitments de hoy
            commitmentsService.Add(projectId, new Commitment() { CreatedOn = DateTime.Now.Date, Left = 1 });
            commitmentsService.Add(projectId, new Commitment() { CreatedOn = DateTime.Now.Date, Left = 1 });
            commitmentsService.Add(projectId, new Commitment() { CreatedOn = DateTime.Now.Date, Left = 1 });
            commitmentsService.Add(projectId, new Commitment() { CreatedOn = DateTime.Now.Date, Left = 0 });
        }

        private static void InitializeCommitmentsData(string projectId, MockCommitmentsService commitmentsService)
        {
            // Week1 O3 C1
            commitmentsService.Add(projectId, new Commitment() { CreatedOn = DateTime.Parse("2008-01-07",CultureInfo.CurrentCulture), Left = 1 });
            commitmentsService.Add(projectId, new Commitment() { CreatedOn = DateTime.Parse("2008-01-07", CultureInfo.CurrentCulture), Left = 1 });
            commitmentsService.Add(projectId, new Commitment() { CreatedOn = DateTime.Parse("2008-01-08", CultureInfo.CurrentCulture), Left = 1 });
            commitmentsService.Add(projectId, new Commitment() { CreatedOn = DateTime.Parse("2008-01-09", CultureInfo.CurrentCulture), Left = 0 });

            // Week2 O3 C3
            commitmentsService.Add(projectId, new Commitment() { CreatedOn = DateTime.Parse("2008-01-14", CultureInfo.CurrentCulture), Left = 0 });
            commitmentsService.Add(projectId, new Commitment() { CreatedOn = DateTime.Parse("2008-01-15", CultureInfo.CurrentCulture), Left = 1 });
            commitmentsService.Add(projectId, new Commitment() { CreatedOn = DateTime.Parse("2008-01-15", CultureInfo.CurrentCulture), Left = 1 });
            commitmentsService.Add(projectId, new Commitment() { CreatedOn = DateTime.Parse("2008-01-17", CultureInfo.CurrentCulture), Left = 1 });
            commitmentsService.Add(projectId, new Commitment() { CreatedOn = DateTime.Parse("2008-01-17", CultureInfo.CurrentCulture), Left = 0 });
            commitmentsService.Add(projectId, new Commitment() { CreatedOn = DateTime.Parse("2008-01-17", CultureInfo.CurrentCulture), Left = 0 });

            // Week3 O2 C2
            commitmentsService.Add(projectId, new Commitment() { CreatedOn = DateTime.Parse("2008-01-21", CultureInfo.CurrentCulture), Left = 1 });
            commitmentsService.Add(projectId, new Commitment() { CreatedOn = DateTime.Parse("2008-01-21", CultureInfo.CurrentCulture), Left = 0 });
            commitmentsService.Add(projectId, new Commitment() { CreatedOn = DateTime.Parse("2008-01-23", CultureInfo.CurrentCulture), Left = 1 });
            commitmentsService.Add(projectId, new Commitment() { CreatedOn = DateTime.Parse("2008-01-23", CultureInfo.CurrentCulture), Left = 0 });

            // Week4 O1 C4
            commitmentsService.Add(projectId, new Commitment() { CreatedOn = DateTime.Parse("2008-01-28", CultureInfo.CurrentCulture), Left = 0 });
            commitmentsService.Add(projectId, new Commitment() { CreatedOn = DateTime.Parse("2008-01-29", CultureInfo.CurrentCulture), Left = 0 });
            commitmentsService.Add(projectId, new Commitment() { CreatedOn = DateTime.Parse("2008-01-30", CultureInfo.CurrentCulture), Left = 0 });
            commitmentsService.Add(projectId, new Commitment() { CreatedOn = DateTime.Parse("2008-01-31", CultureInfo.CurrentCulture), Left = 0 });
            commitmentsService.Add(projectId, new Commitment() { CreatedOn = DateTime.Parse("2008-01-31", CultureInfo.CurrentCulture), Left = 1 });
        }

        [TestMethod]
        public void ShouldGenerateWeeklyCommitmentsBarsUrl()
        {
            string mockProjectUri = "AF06A611-12CE-4C06-B3AD-E2754D12D516";
            MockCommitmentsService commitmentsService = new MockCommitmentsService();
            InitializeCommitmentsData(mockProjectUri, commitmentsService);
            TestableCommitmentsController controller = new TestableCommitmentsController(commitmentsService);

            controller.CommitmentsMetrics(mockProjectUri);

            string expectedUrl = @"http://chart.apis.google.com/chart?cht=bhs&chs=400x350&chd=t:15.0,15.0,15.0,10.0,5.0|70.0,5.0,15.0,10.0,20.0&chtt=Weekly+commitments&chco=ff0000,00aa00&chdl=Open|Closed&chxt=x,y&chxl=0:|1:|Week+5|Week+4|Week+3|Week+2|Week+7&chxr=0,0,20";
            Assert.AreEqual(expectedUrl, ((CommitmentsMetricsData)controller.DataToShow).GChartWeeklyCommitmentsBars);
        }

        [TestMethod]
        public void ShouldGenerateTotalCommitmentsBarsUrl()
        {
            string mockProjectUri = "AF06A611-12CE-4C06-B3AD-E2754D12D516";
            MockCommitmentsService commitmentsService = new MockCommitmentsService();
            InitializeCommitmentsData(mockProjectUri, commitmentsService);
            TestableCommitmentsController controller = new TestableCommitmentsController(commitmentsService);

            controller.CommitmentsMetrics(mockProjectUri);

            string expectedUrl = @"http://chart.apis.google.com/chart?cht=bhs&chs=400x350&chd=t:24.0|48.0&chtt=Project+commitments&chco=ff0000,00aa00&chdl=Open|Closed&chxt=x,y&chxl=0:|1:|Total&chxr=0,0,50";
            Assert.AreEqual(expectedUrl, ((CommitmentsMetricsData)controller.DataToShow).GChartTotalCommitmentsBars);
        }

        [TestMethod]
        public void ShouldGenerateEmptyWeeklyCommitmentsBarsUrl()
        {
            string mockProjectUri = MockCommitmentsService.ProjectIdForEmptyData;
            MockCommitmentsService commitmentService = new MockCommitmentsService();
            TestableCommitmentsController controller = new TestableCommitmentsController(commitmentService);

            controller.CommitmentsMetrics(mockProjectUri);

            string expectedUrl = String.Format(CultureInfo.InvariantCulture,"/{0}/{1}", ConfigurationManager.AppSettings["SiteImagesPath"], "chart_EmptyCommitmentsBars.png");
            Assert.AreEqual(expectedUrl, ((CommitmentsMetricsData)controller.DataToShow).GChartWeeklyCommitmentsBars);
        }

        [TestMethod]
        public void ShouldGenerateEmptyTotalCommitmentsBarsUrl()
        {
            string mockProjectUri = MockCommitmentsService.ProjectIdForEmptyData;
            MockCommitmentsService commitmentService = new MockCommitmentsService();
            TestableCommitmentsController controller = new TestableCommitmentsController(commitmentService);

            controller.CommitmentsMetrics(mockProjectUri);

            string expectedUrl = String.Format(CultureInfo.InvariantCulture,"/{0}/{1}", ConfigurationManager.AppSettings["SiteImagesPath"], "chart_EmptyCommitmentsBars.png");
            Assert.AreEqual(expectedUrl, ((CommitmentsMetricsData)controller.DataToShow).GChartWeeklyCommitmentsBars);
        }
    }

    class TestableCommitmentsController : CommitmentsController
    {
        public object DataToShow { get; set; }
        public object ViewToShow { get; set; }

        public TestableCommitmentsController() : base(new MockCommitmentsService(), new MockProjectsService(), new MockProfileService())
        {
        }

        public TestableCommitmentsController(ICommitmentsService service)
            : base(service, new MockProjectsService(), new MockProfileService())
        {
        }

         protected override void RenderView(string viewName, string masterName, object viewData)
        {
            ViewToShow = viewName;
            DataToShow = viewData;
        }
    }
}
